// OMG WTF IS THIS
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>

using namespace std;

enum prompt {
	EmployeeID,
	GrossPay,
	NetPay,
	FederalTax,
	StateTax,
	FICAHoldings
};

string employeeID;
char inputBuffer[256];
double grossPay;
double netPay;
float federalTax;
float stateTax;
double ficaHoldings;

void getUserInput(prompt type);
void checkUserInput(prompt type);
void calcNetPay();
void displayReport();
void saveReport();
void reset();

int main() {
	cout << fixed << showpoint << setprecision(2);
	while (true) {
		cout << "\nEmployee Payroll Report -\n";

		getUserInput(EmployeeID);
		if (employeeID == "0") {
			break;
		}

		getUserInput(GrossPay);
		getUserInput(FederalTax);
		getUserInput(StateTax);
		getUserInput(FICAHoldings);

		calcNetPay();

		displayReport();
		saveReport();

		reset();
	}

	cout << "Press any key to exit...\n";
	cin.get();
}

void getUserInput(prompt type) {
	switch (type) {
		case EmployeeID:
			fflush(stdin);
			cout << "Employee ID: ";
			getline(cin, employeeID);
		break;

		// Double is only 100% precise to first 15 digits
		case GrossPay:
			cout << "Gross Pay: $";
			cin.getline(inputBuffer, 16);
			stringstream(inputBuffer) >> grossPay;
		break;

		// Using input buffer not necessary for tax, can not be < 0 or > 100
		case StateTax:
			cout << "State Tax (%): ";
			cin >> stateTax;
			cin.ignore();
		break;

		case FederalTax:
			cout << "Federal Tax (%): ";
			cin >> federalTax;
			cin.ignore();
		break;

		// Using input buffer not necessary for FICA holdings, can not be greater than gross pay
		case FICAHoldings:
			cout << "FICA Holdings: $";
			cin >> ficaHoldings;
			cin.ignore();
		break;
		default:
			cout << "Invalid option passed to getUserInput";
		break;
	}

	calcNetPay();
	checkUserInput(type);
}

void checkUserInput(prompt type) {
	switch (type) {
		case EmployeeID:

		break;

		case GrossPay:
			if (grossPay < 0) {
				grossPay = 0;
				cout << "Gross pay cannot be less than $0\n";
				cout <<"Please try again...\n\n";
				getUserInput(type);
			}

			// Could not be properly converted, or is 0??
			if (!grossPay) {
				cin.clear(ios::failbit);
			}
		break;

		case StateTax:
			if (stateTax < 0) {
				stateTax = 0;
				cout << "State tax cannot be less than 0%\n";
				cout <<"Please try again...\n\n";
				getUserInput(type);
			}

			if (stateTax > 100) {
				stateTax = 0;
				cout << "Sate tax cannot exceed 100%\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}

			if (stateTax + federalTax > 100) {
				stateTax = 0;
				cout << "Combined state and federal tax cannot exceed 100%\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}
		break;

		case FederalTax:
			if (federalTax < 0) {
				federalTax = 0;
				cout << "Federal tax cannot be less than 0%\n";
				cout <<"Please try again...\n\n";
				getUserInput(type);
			}

			if (federalTax > 100) {
				federalTax = 0;
				cout << "Federal tax cannot exceed 100%\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}

			if (stateTax + federalTax > 100) {
				federalTax = 0;
				cout << "Combined state and federal tax cannot exceed 100%\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}
		break;

		case FICAHoldings:
			if (ficaHoldings < 0) {
				ficaHoldings = 0;
				cout << "FICA holdings cannot be less than $0\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}

			if (ficaHoldings > grossPay) {
				ficaHoldings = 0;
				cout << "FICA holdings cannot exceed $" << grossPay << "\n";
				cout << "Please try again...\n\n";
				getUserInput(type);
			}

		break;

		default:
			cout << "Invalid option passed to checkUserInput\n";
		break;
	}

	if (!cin.good()) {
		cin.clear();
		cin.sync();
		cout << "Incorrect entry...please try again\n";
		getUserInput(type);
	}

}

void calcNetPay() {
	netPay = grossPay;
	netPay = netPay - (grossPay * (stateTax/100));
	netPay = netPay - (grossPay * (federalTax/100));

	if (ficaHoldings <= netPay) {
		netPay = netPay - ficaHoldings;
	}

	else if (ficaHoldings !=0 ) {
		cout << "FICA holdings cannot exceed $" << netPay << "\n";
		cout << "Please try again...\n\n";

		getUserInput(FICAHoldings);
	}
}

void displayReport() {
	cout << "\n - Payroll Report -\n";
	cout << "Employee ID: " << employeeID << "\n";
	cout << "Gross Pay: $" << grossPay << "\n";
	cout << "State Tax: " << stateTax << "%" << " - " << grossPay * (stateTax/100) << "\n";
	cout << "Federal Tax: " << federalTax << "%" << " - " << grossPay * (federalTax/100) << "\n";
	cout << "FICA Holdings: $" << ficaHoldings << "\n";
	cout << "Employee Net Pay: $" << netPay << "\n";
}

void saveReport() {
	string save;
	ofstream report;

	cout << "\nSave report? ";
	cin >> save;
	if (save == "yes" | save == "y") {
		cout << "\nSaving...\n";

		report.open ("report.txt", ios::out | ios::app);
		report << "Employee ID: " << employeeID << "\n";
		report << "Gross Pay: $" << grossPay << "\n";
		report << "State Tax: " << stateTax << "%" << "\n";
		report << "Federal Tax: " << federalTax << "%" << "\n";
		report << "FICA Holdings: $" << ficaHoldings << "\n";
		report << "Employee Net Pay: $" << netPay << "\n";
		report << "\n";
		report.close();

		cout << "Report saved.\n";
	}
	else {
		cout << "\nReport not saved.\n";
	}

}

void reset() {
	grossPay = 0;
	netPay = 0;
	federalTax = 0;
	stateTax = 0;
	ficaHoldings = 0;
}



